/**
 * Copyright (c) 2024-2025 National Fundamental Software of China Co., Ltd.
 *
 * You should have find a copy of NFSChina License. If not, please contact us
 * by email <os_support@nfschina>
 *
**/

#include "systeminfowidget.h"
#include "renamedialog.h"

#include <KPluginFactory>
#include <QDebug>
#include <QtNetwork/QHostInfo>
#include <QFile>
#include <QTextStream>
#include <QProcess>
#include <math.h>
#include <sstream>
#include <QRegExp>
#include <sys/statfs.h>
#include <sys/stat.h>
#include <unistd.h>
#include <time.h>
#include <fstream>
#include <QJsonDocument>
#include <QJsonObject>
#include <QPushButton>
#include <QIcon>
#include <QLocale>
#include <QStorageInfo>
#include <QStringList>
#include <QRegularExpression>
#include <QRegularExpressionMatch>
#include <cmath>
#include <KSharedConfig>
#include <KColorScheme>
#include <QSysInfo>

#define SYSTEM_FILE_PATH "/etc/os-release"
#define CPU_FILE_PATH "/proc/cpuinfo"
#define OS_FILE_PATH "/etc/license.d/os"

K_PLUGIN_CLASS_WITH_JSON(SystemInfoWidget, "kcm_systeminfo.json")

SystemInfoWidget::SystemInfoWidget(QWidget *parent, const QVariantList &args) :
    KCModule(parent, args)
{
    setButtons(Apply | Default);
    setupUi(this);

    auto config = KSharedConfig::openConfig();
    auto highlitgtscheme = KColorScheme(QPalette::Active, KColorScheme::Selection, config);
    auto active = KColorScheme(QPalette::Active, KColorScheme::View, config);
    QColor thisbackground = active.background().color();
    QColor highlightcolor = highlitgtscheme.background(KColorScheme::NormalBackground).color();
    QColor textcolor = active.foreground(KColorScheme::NormalText).color();
    QString highlightcolorstr = QString("rgb(%1, %2, %3)").arg(highlightcolor.red()).arg(highlightcolor.green()).arg(highlightcolor.blue());
    QString themebackground = QString("rgb(%1, %2, %3)").arg(thisbackground.red()).arg(thisbackground.green()).arg(thisbackground.blue());
    QString themetext = QString("rgb(%1, %2, %3)").arg(textcolor.red()).arg(textcolor.green()).arg(textcolor.blue());

    QString backgroudcolor = themebackground=="rgb(255, 255, 255)"?"rgb(255, 255, 255)":"rgb(45, 45, 45)";

    QString themeborder = themebackground=="rgb(255, 255, 255)"?"#FFFFFF":"#353535";
    QString bodercolor = themebackground=="rgb(255, 255, 255)"?"#CCCCCC":"#2D2D2D";
    QString linecolor = themebackground=="rgb(255, 255, 255)"?"#F0F0F0":"#2D2D2D";
    bool isLight = themebackground=="rgb(255, 255, 255)";

    QString style;
    if (isLight) {
        style = QString(R"(
            QFrame {
                border: 1px solid #CCCCCC;
                background-color: #FFFFFF;
                border-radius: 5px;
            }

            QFrame[frameShape="4"] {  /* 匹配 HLine 类型的 QFrame */
                border-top: 1px solid #F0F0F0;
                background: none;
            }

            QPushButton#pushButton {
                background-color: #007AFF;
                border-style: solid;
                color: #FFFFFF;
                border-radius: 6px;
                border-width: 0px;
            }

            QPushButton#pushButton:hover {
                border-color: #007AFF;
            }

            QLabel#label
            {
                border: none;
                padding: 0px;
            }
        )");
    } else {
        style = QString(R"(
            QFrame {
                border: 1px solid #2D2D2D;
                background-color: #353535;
                border-radius: 5px;
            }

            QFrame[frameShape="4"] {  /* 匹配 HLine 类型的 QFrame */
                border-top: 1px solid #2D2D2D;
                background: none;
            }

            QPushButton#pushButton {
                background-color: #007AFF;
                border-style: solid;
                color: #FFFFFF;
                border-radius: 6px;
                border-width: 0px;
            }

            QPushButton#pushButton:hover {
                border-color: #007AFF;
            }

            QLabel#label
            {
                border: none;
                padding: 0px;
            }
        )");
    }

    this->setStyleSheet(style);

    line->setFrameShape(QFrame::HLine);
    line_2->setFrameShape(QFrame::HLine);
    line_3->setFrameShape(QFrame::HLine);
    line_4->setFrameShape(QFrame::HLine);
    line_5->setFrameShape(QFrame::HLine);
    line_7->setFrameShape(QFrame::HLine);
    line_8->setFrameShape(QFrame::HLine);

    QPushButton *button = new QPushButton(frame);
    button->setStyleSheet("QPushButton { background-color: transparent;border: 0px solid gray;}");
    button->setFixedSize(589,48);

    QPushButton *tailicon1 = new QPushButton(button);
    connect(tailicon1,&QPushButton::clicked,button,&QPushButton::clicked);
    tailicon1->setIcon(QIcon::fromTheme(QStringLiteral("go-next")));
    tailicon1->setGeometry(556 - 16, 16, 16, 16);
    tailicon1->setStyleSheet(QString("\
                                     QPushButton{ \
                                         background-color: transparent;\
                                         border : 0px;\
                                     }\
                                     "));


                                     QPushButton *button1 = new QPushButton(frame_2);
                             button1->setStyleSheet("QPushButton {boder:none;backgroup-color:transparent;border: 0px solid gray;}");
            button1->setFixedSize(589,48);
    button1->move(0,240);
    QPushButton *tailicon2 = new QPushButton(button1);
    connect(tailicon2,&QPushButton::clicked,button1,&QPushButton::clicked);
    tailicon2->setIcon(QIcon::fromTheme(QStringLiteral("go-next")));
    tailicon2->setGeometry(556 - 16, 16, 16, 16);
    tailicon2->setStyleSheet(QString("\
                                     QPushButton{ \
                                         background-color: transparent;\
                                         border : 0px;\
                                     }\
                                     "));

    getOsSysInfo();
    m_license = new com::nfs::license::Info("com.nfs.license", "/com/nfs/license/Info", QDBusConnection::systemBus(), this);
    connect(pushButton,&QPushButton::clicked, [&](){
        m_license->ShowLicenseActivator(m_sysInfo.licenseType, m_sysInfo.osName, m_sysInfo.version);
    });
    connect(m_license,&com::nfs::license::Info::LicenseStateChange,this,&SystemInfoWidget::updateLicenseState);
    connect(button,&QPushButton::clicked, [&](){
        QProcess process;
        process.start("hostname"); // 执行hostname命令
        process.waitForFinished(); // 等待命令执行完成

        QString deviceName = process.readAllStandardOutput().trimmed(); // 读取命令的输出，并去除前后的空白字符
        ReNameDialog renamedialog(deviceName);
        connect(&renamedialog,&ReNameDialog::renamed,this,&SystemInfoWidget::onRenamed);
        renamedialog.exec();
    });

    connect(button1,&QPushButton::clicked, [&](){
        QProcess process;
        process.start("/usr/bin/cdosupdate-launcher");
        process.waitForFinished();
    });

    int state = m_license->GetLicenseState(m_sysInfo.licenseType);
    updateLicenseState(state);
}

SystemInfoWidget::~SystemInfoWidget()
{
}

QString SystemInfoWidget::getExecResult(QString cmd) {
    QProcess process;
    process.start("bash", QStringList() << "-c" << cmd);
    process.waitForFinished();
    QString result = process.readAllStandardOutput();
    return result.trimmed();
}

void SystemInfoWidget::resetUI()
{
    name_label->setText(m_sysInfo.deviceName);
    system_label->setText(m_sysInfo.osName);
    version_label->setText(m_sysInfo.version);

    kernel_label->setText(m_sysInfo.kernel);
    type_label->setText(m_sysInfo.type);
    //disk_label->setText(m_sysInfo.disk);
    memory_label->setText(m_sysInfo.memory);
    CPU_label->setText(m_sysInfo.CPU);
    //GPU_label->setText(m_sysInfo.GPU);
    installTime_label->setText(m_sysInfo.installTime);
}

void SystemInfoWidget::load()
{
    resetUI();
    Q_EMIT changed(false);
}

void SystemInfoWidget::save()
{
}

void SystemInfoWidget::defaults()
{
    resetUI();
    KCModule::defaults();
}

void SystemInfoWidget::onRenamed(QString name)
{
    name_label->setText(name);
}

void SystemInfoWidget::getOsSysInfo()
{
    if (m_sysInfo.initialized)
        return;

    com::nfs::devicemanager deviceManager("com.nfs.devicemanager","/com/nfs/devicemanager",QDBusConnection::systemBus(),this);
    QString HwinfoStr = deviceManager.getInfo("hwinfo");

    // 使用正则表达式匹配 Hardware Class 为 graphics card 的行，并捕获接下来的 Model 字段的值
    QRegularExpression rx("Hardware Class:\\s+graphics card(?s).*?Model:\\s+\"([^\"]+)\"");
    QString accumulatedModels;
    QRegularExpressionMatchIterator i = rx.globalMatch(HwinfoStr);
    while (i.hasNext()) {
        QRegularExpressionMatch match = i.next();
        QString model = match.captured(1);
        if (!accumulatedModels.isEmpty()) {
            accumulatedModels += "/";
        }
        accumulatedModels += model;
    }
    if (!accumulatedModels.isEmpty()) {
        m_sysInfo.GPU = accumulatedModels;
    }

    QString LshwStr = deviceManager.getInfo("lshw");
    QStringList lines = LshwStr.split('\n');
    bool foundCpuDescription = false;
    QString nextDescription;
    QString currentArchiteture = QSysInfo::currentCpuArchitecture();
    if(currentArchiteture.contains(QStringLiteral("loong")))
    {
        for (const QString &line : lines) {
            if (line.contains("bus info: cpu")) {
                foundCpuDescription = true;
            } else if (foundCpuDescription && line.contains("version:")) {
                nextDescription = line.split(':').last().trimmed();
                foundCpuDescription = false; // 重置标志，以防有多余的description行
                break; // 找到后退出循环
            }
        }

        if (!nextDescription.isEmpty()) {
            m_sysInfo.CPU = nextDescription;
        }
    } else{
        for (const QString &line : lines) {
            if (line.contains("description: CPU")) {
                foundCpuDescription = true;
            } else if (foundCpuDescription && line.contains("product:")) {
                nextDescription = line.split(':').last().trimmed();
                foundCpuDescription = false; // 重置标志，以防有多余的description行
                break; // 找到后退出循环
            }
        }

        if (!nextDescription.isEmpty()) {
            m_sysInfo.CPU = nextDescription;
            qDebug() << "Description after 'description: CPU':" << nextDescription;
        } else {
            qDebug() << "No description found after 'description: CPU'.";
        }
    }

    QHostInfo hostInfo;
    m_sysInfo.deviceName = hostInfo.localHostName();
    QMap<QString, QString> data;
    QFile file(SYSTEM_FILE_PATH);
    if (file.open(QIODevice::ReadOnly | QIODevice::Text)) {
        QTextStream in(&file);
        while (!in.atEnd()) {
            QString line = in.readLine();
            QStringList parts = line.split('=');
            if (parts.size() != 2)
                continue;

            QString key = parts[0].trimmed();
            QString value = parts[1].trimmed().remove(QChar('"'));
            data.insert(key, value);
        }
        file.close();
    }

    QString localeStr = QLocale::system().name();
    m_sysInfo.osName = localeStr.startsWith("zh") ? data["NAME"] : data["NAME_EN"];

    bool update = false;
    if  (data.find("PRETTY_NAME") != data.end()) {
        QString prettyName = data["PRETTY_NAME"];
        QStringList prettyNameParts = prettyName.split(' ');
        if (prettyNameParts.size() == 2) {
            m_sysInfo.licenseType = prettyNameParts[1].contains("service",Qt::CaseInsensitive) ? "nf" : "os";
            m_sysInfo.version = prettyNameParts[1];
            update = true;
        }
    }
    if (!update) {
        m_sysInfo.version = data["VERSION"] + "-"+ data["MINOR_VERSION"];
    }

    QRegularExpression regex("description:\\s*System Memory[\\s\\S]*?size:\\s*(\\d+)(GiB)");
    QRegularExpressionMatch match = regex.match(LshwStr);
    if (match.hasMatch()) {
        // 提取匹配到的内存大小仅数字部分，忽略单位GiB
        QString memorySize = match.captured(1); // 第一个捕获组（数字部分）
        m_sysInfo.memory = memorySize + QString("GB");
    }

    m_sysInfo.kernel = getExecResult("uname -r");
    m_sysInfo.type = getExecResult("uname -m");

    struct statfs fs_stat;
    if (statfs("/", &fs_stat) == -1) {
        perror("statfs");
        return;
    }

    // 注意：statfs返回的f_fsid不是文件系统的创建时间，
    // 但我们可以尝试读取挂载点本身的ctime作为替代方案
    struct stat dir_stat;
    if (stat("/", &dir_stat) == -1) {
        perror("stat");
        return;
    }

    // 将ctime转换为人类可读的日期和时间
    char buffer[80];
    struct tm *tm = localtime(&dir_stat.st_ctime);
    strftime(buffer, sizeof(buffer), "%Y%m%d", tm);
    m_sysInfo.installTime = QString::fromLocal8Bit(buffer);

    QFile file2(OS_FILE_PATH);
    if (file2.open(QIODevice::ReadOnly | QIODevice::Text)) {
        QTextStream in(&file2);
        QString content = in.readAll();
        file2.close();

        if (!content.isEmpty()) {
            m_sysInfo.licenseType = content.trimmed();
        }
    }

    m_sysInfo.initialized = true;
}

void SystemInfoWidget::updateLicenseState(uint state)
{
    switch(state)
    {
    case 0:
    {
        pushButton->setText(i18n("Activation"));
        state_label->setText(i18n("UnActivation"));
        break;
    }
    case 1:
    case 2:
    {
        QString osInfoStr = m_license->GetLicenseStatus(m_sysInfo.licenseType);
        QJsonDocument doc = QJsonDocument::fromJson(osInfoStr.toUtf8());

        if (!doc.isObject()) {
            qDebug() << "JSON parsing failed";
            break;
        }

        QJsonObject jsonObj = doc.object();
        if (jsonObj.contains("expiration")) {
            QString expirationStr = jsonObj["expiration"].toString();
            qDebug() << "Expiration Timestamp:" << expirationStr;

            qint64 expirationTimestamp = expirationStr.toLongLong();
            // 转换为QDateTime（这里我们假设UTC时间）
            QDateTime expirationDateTime = QDateTime::fromTime_t(static_cast<time_t>(expirationTimestamp));
            // 将QDateTime转换为更易读的字符串格式
            QString formattedExpiration = expirationDateTime.toString("yyyy-MM-dd");
            osInfoStr = state == 1 ? i18n("Activated (service period expires") + formattedExpiration + ")"
                                   : i18n("Authorization has expired (expiration date") + formattedExpiration + ")";
        }
        pushButton->setText(state == 1
                            ? i18n("Viewer") : i18n("Activation"));
        state_label->setText(osInfoStr);
        break;
    }
    case 3:
        pushButton->setText(i18n("Activation"));
        state_label->setText(i18n("ProbationaryPeriodAuthorized"));
        break;
    case 4:
        pushButton->setText(i18n("Activation"));
        state_label->setText(i18n("ProbationaryPeriodExpired"));
        break;
    default:
        break;
    }
}

#include "systeminfowidget.moc"
